/**
 * TODO: write Web class for hxtc targets
 * @author Cref
 */

package js;

class Web {
	
	/**
		Returns the GET and POST parameters.
		TODO: make fully compatible with php/neko output
	**/
	public static function getParams():Hash<String> {
		var h = new Hash<String>();
		for (n in Request.form) h.set(n,Request.form.item(n).item);
		for (n in Request.queryString) h.set(n,Request.queryString.item(n).item);
		return h;
	}

	/**
		Returns an Array of Strings built using GET / POST values.
		If you have in your URL the parameters [a[]=foo;a[]=hello;a[5]=bar;a[3]=baz] then
		[neko.Web.getParamValues("a")] will return [["foo","hello",null,"baz",null,"bar"]]
	**/
	public static function getParamValues( param : String ) : Array<String> {
		var reg = new EReg("^"+param+"(\\[|%5B)([0-9]*?)(\\]|%5D)=(.*?)$", "");
		var res = new Array<String>();
		var explore = function(data:String){
			if (data == null || data.length == 0)
				return;
			for (part in data.split("&")){
				if (reg.match(part)){
					var idx = reg.matched(2);
					var val = StringTools.urlDecode(reg.matched(4));
					if (idx == "")
						res.push(val);
					else
						res[Std.parseInt(idx)] = val;
				}
			}
		}
		explore(StringTools.replace(getParamsString(), ";", "&"));
		explore(getPostData());
		if (res.length == 0)
			return null;
		return res;
	}
	
	/**
		Returns the local server host name
	**/
	public static inline function getHostName():String {
		return Request.serverVariables.item('SERVER_NAME').item;
	}

	/**
		Surprisingly returns the client IP address.
	**/
	public static inline function getClientIP():String {
		return Request.serverVariables.item('REMOTE_ADDR').item;
	}
	
	/**
		Returns the original request URL (before any server internal redirections)
	**/
	//TODO: check if this does the same as on php/neko (currently only returns the requested path)
	public static function getURI() {
		return Request.serverVariables.item('URL').item;
	}

	/**
		Tell the client to redirect to the given url ("Location" header)
	**/
	//TODO: check if the same redirect headers are used as on php/neko
	public static inline function redirect( url : String ) {
		Response.redirect(url);
	}

	/**
		Set an output header value. If some data have been printed, the headers have
		already been sent so this will raise an exception.
	**/
	public static inline function setHeader( h : String, v : String ) {
		Response.addHeader(h, v);
	}

	/**
		Set the HTTP return code. Same remark as setHeader.
	**/
	public static inline function setReturnCode( r : Int ) {
		Response.status = '' + r;
	}
	
	/**
		Retrieve a client header value sent with the request.
	**/
	public static function getClientHeader( k : String ) {
		var v = Request.serverVariables.item(k).item;
		return v == null?Request.serverVariables.item('HTTP_'+k).item:v;
	}

	/**
		Retrieve all the client headers.
	**/
	//TODO: clear out values that are in serverVariables but shouldn't be in clientHeaders
	//strip off HTTP_
	public static function getClientHeaders() {
		var a = new List();
		for (n in Request.serverVariables) a.add({header:n,value:Request.serverVariables.item(n).item});
		return a;
	}

	/**
		Returns all the GET parameters String
	**/
	//TODO: should this function replace '&' by ';' ?
	public static inline function getParamsString() {
		return Request.serverVariables.item('QUERY_STRING').item;
	}

	/**
		Returns all the POST data. POST Data is always parsed as
		being application/x-www-form-urlencoded and is stored into
		the getParams hashtable. POST Data is maximimized to 256K
		unless the content type is multipart/form-data. In that
		case, you will have to use [getMultipart] or [parseMultipart]
		methods.
	**/
	//TODO: check when this funciton should return null
	public static inline function getPostData():String {
		return ''+Request.form;
	}

	/**
		Returns an hashtable of all Cookies sent by the client.
		Modifying the hashtable will not modify the cookie, use setCookie instead.
	**/
	public static function getCookies():Hash<String> {
		var h = new Hash<String>();
		for (n in Request.cookies) h.set(n,Request.cookies.item(n).item);
		return h;
	}

	/**
		Set a Cookie value in the HTTP headers. Same remark as setHeader.
	**/
	public static function setCookie( key : String, value : String, ?expire: Date, ?domain: String, ?path: String, ?secure: Bool ) {
		var c = Response.cookies.item(key);
		c.item = value;
		c.expires = expire;
		c.domain = domain;
		c.path = path;
		c.secure = secure;
	}

	/**
		Returns an object with the authorization sent by the client (Basic scheme only).
	**/
	public static function getAuthorization() : { user : String, pass : String } {
		var h = getClientHeader("Authorization");
		var reg = ~/^Basic ([^=]+)=*$/;
		if( h != null && reg.match(h) ){
			var val = hxtc.Base64.decode(reg.matched(1));
			var a = val.split(":");
			if( a.length != 2 ){
				throw "Unable to decode authorization.";
			}
			return {user: a[0],pass: a[1]};
		}
		return null;
	}

	/**
		Get the current script directory in the local filesystem.
	**/
	public static inline function getCwd() {
		return Request.serverVariables.item('APPL_PHYSICAL_PATH').item;
	}

	/**
		Set the main entry point function used to handle requests.
		Setting it back to null will disable code caching.
	**/
	/* Only available on Neko target. what does it do?
	public static function cacheModule( f : Void -> Void ) {
		_set_main(f);
	}
	*

	/**
		Get the multipart parameters as an hashtable. The data
		cannot exceed the maximum size specified.
	**/
	//TODO (Cimple/cBestandsoverdracht.asp)
	public static function getMultipart( maxSize : Int ) : Hash<String> {
		throw 'TODO!';
		var h = new Hash();
		/*
		var buf : haxe.io.BytesBuffer = null;
		var curname = null;
		parseMultipart(function(p,_) {
			if( curname != null )
				h.set(curname,neko.Lib.stringReference(buf.getBytes()));
			curname = p;
			buf = new haxe.io.BytesBuffer();
			maxSize -= p.length;
			if( maxSize < 0 )
				throw "Maximum size reached";
		},function(str,pos,len) {
			maxSize -= len;
			if( maxSize < 0 )
				throw "Maximum size reached";
			buf.addBytes(str,pos,len);
		});
		if( curname != null )
			h.set(curname,neko.Lib.stringReference(buf.getBytes()));
		*/
		return h;
	}

	/**
		Parse the multipart data. Call [onPart] when a new part is found
		with the part name and the filename if present
		and [onData] when some part data is readed. You can this way
		directly save the data on hard drive in the case of a file upload.
	**/
	//TODO (Cimple/cBestandsoverdracht.asp)
	public static function parseMultipart( onPart : String -> String -> Void, onData : haxe.io.Bytes -> Int -> Int -> Void ) : Void {
		throw 'TODO!';
		/*
		_parse_multipart(
			function(p,f) { onPart(new String(p),if( f == null ) null else new String(f)); },
			function(buf,pos,len) { onData(untyped new haxe.io.Bytes(__dollar__ssize(buf),buf),pos,len); }
		);
		*/
	}

	/**
		Flush the data sent to the client. By default on Apache, outgoing data is buffered so
		this can be useful for displaying some long operation progress.
	**/
	public static inline function flush() : Void {
		Response.flush();
	}

	/**
		Get the HTTP method used by the client. This api requires Neko 1.7.1+
	**/
	//TODO: check if this should return lowerCase or upperCase
	public static inline function getMethod() : String {
		return Request.serverVariables.item('REQUEST_METHOD').item;
	}
	
	/**
		Write a message into the web server log file. This api requires Neko 1.7.1+
	**/
	public static inline function logMessage( msg : String ) {
		Response.appendToLog(msg);
	}
	
	public static inline var isModNeko : Bool=false;
	public static inline var isTora : Bool=false;
	
}